/*                  封装图片显示函数            */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>

#define UINT unsigned short
#define DWORD unsigned int
#define LONG unsigned int
#define WORD unsigned short

#define WIDTH 800
#define HEIGHT 480

struct BitMapFileHeader
{
    WORD bfType;      // 位图文件的类型，必须为BM(1-2字节）
    DWORD bfSize;     // 位图文件的大小，以字节为单位（3-6字节）
    WORD bfReserved1; // 位图文件保留字，必须为0(7-8字节）
    WORD bfReserved2; // 位图文件保留字，必须为0(9-10字节）
    DWORD bfOffBits;  // 位图数据的起始位置，以相对于位图（11-14字节）
    // 文件头的偏移量表示，以字节为单位
} __attribute__((packed));

struct BitMapInfoHeader
{
    DWORD biSize;    // 本结构所占用字节数（15-18字节）
    LONG biWidth;    // 位图的宽度，以像素为单位（19-22字节）    ------图片的宽度
    LONG biHeight;   // 位图的高度，以像素为单位（23-26字节）   ------图片的高度
    WORD biPlanes;   // 目标设备的级别，必须为1(27-28字节）
    WORD biBitCount; // 每个像素所需的位数，必须是1（双色），（29-30字节）  ---位深
    // 4(16色），8(256色）或24（真彩色）之一
    DWORD biCompression; // 位图压缩类型，必须是 0（不压缩），（31-34字节）
    // 1(BI_RLE8压缩类型）或2(BI_RLE4压缩类型）之一
    DWORD biSizeImage;    // 位图的大小，以字节为单位（35-38字节）   ---图片颜色数据的大小
    LONG biXPelsPerMeter; // 位图水平分辨率，每米像素数（39-42字节）
    LONG biYPelsPerMeter; // 位图垂直分辨率，每米像素数（43-46字节)
    DWORD biClrUsed;      // 位图实际使用的颜色表中的颜色数（47-50字节）
    DWORD biClrImportant; // 位图显示过程中重要的颜色数（51-54字节）
} __attribute__((packed));

int (*lcd_mmap)[800];

// 图片路径  xy坐标点
int show_bmp(char *bmp_file_name, int x, int y)
{
    int lcd_fd = open("/dev/fb0", O_RDWR);
    if (lcd_fd < 0)
    {
        perror("Failed to open frame buffer device");
        return -1;
    }
    int(*lcd_mmap)[WIDTH] = (int(*)[WIDTH])mmap(NULL, WIDTH * HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);

    // 打开图片文件
    FILE *fp = fopen(bmp_file_name, "r");
    if (fp == NULL)
    {
        printf("open bmp file error filename:%s\n", bmp_file_name);
        return -1;
    }

    struct BitMapFileHeader bmp_file_header;
    struct BitMapInfoHeader bmp_info_header;

    // 读取图片文件的头部信息
    fread(&bmp_file_header, sizeof(struct BitMapFileHeader), 1, fp);
    fread(&bmp_info_header, sizeof(struct BitMapInfoHeader), 1, fp);

    // 获取图片的宽高
    int width = bmp_info_header.biWidth;
    int height = bmp_info_header.biHeight;

    // malloc申请图片二维数组内存
    unsigned char(*bmp_buf)[width * 3] = (unsigned char(*)[width * 3]) malloc(height * width * 3);
    if (bmp_buf == NULL)
    {
        printf("malloc error\n");
        return -1;
    }

    // 判断是24位bmp图片
    if (bmp_file_header.bfType == 19778 && bmp_info_header.biBitCount == 24)
    {
        // 获取每行补齐的字节数   (BMP图片当每行字节数非4的倍数会自动补0)
        int padding = 4 - width * 3 % 4;

        if (padding = 4)
            padding = 0;

        for (size_t row = 0; row < height; row++)
        {
            int ret = fread(bmp_buf[row], width * 3, 1, fp);
            fseek(fp, padding, SEEK_CUR); // 跳过补齐0的字节
        }
        // 判断图片是否超出屏幕
        if (y + height > 480 || x + width > 800)
        {
            printf("bmp size is too big\n");
            return -1;
        }

        // 遍历图片数组 填充屏幕映射
        for (size_t row = 0; row < height; row++)
        {

            for (size_t col = 0; col < width; col++)
            {
                lcd_mmap[row + y][col + x] = 0x00 << 24 | bmp_buf[height - 1 - row][col * 3 + 2] << 16 | bmp_buf[height - 1 - row][col * 3 + 1] << 8 | bmp_buf[height - 1 - row][col * 3] << 0;
            }
        }
        close(lcd_fd);
        // 释放内存
        free(bmp_buf);
        return 0;
    }
    else
    {
        // 判断不是 24位bmp
        printf("not 24bit bmp name: %s\n", bmp_file_name);
    }
}
